{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a name=\"top\"></a><img src=\"source/SpinalHDL.png\" alt=\"SpinalHDL based on Scala\" style=\"width:320px;\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Before running Spinal HDL code, be sure to load SpinalHDL Libraries  \n",
    "**Note** : This may be a little slow when the first time load, please wait a moment to download Lib from remote.)   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val path = System.getProperty(\"user.dir\") + \"/source/load-spinal.sc\"\n",
    "interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  Bit width inference usage restriction \n",
    "Example1:\n",
    "```scala\n",
    "  val c = UInt()\n",
    "  c.getWidth   // X Failed !\n",
    "  c:= a + b\n",
    "  c.getWidth   // is ok, because c width already inferred by \"c := a + b\"\n",
    "```\n",
    "Example2:(setAll need getWidth) \n",
    "```scala\n",
    " val c = out UInt() \n",
    " when(clc){c.setAll }.otherwise(c := a * b)  //failed\n",
    " when(clc){c := a * b }.otherwise(c.setAll)  //It's OK\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class T2  extends Component{\n",
    "    val a,b = in UInt(8 bits)\n",
    "    val clc= in Bool()\n",
    "    val c = out UInt() \n",
    "//  when(clc){c.setAll }.otherwise(c := a * b)  //failed   \n",
    "  when(clc){c := a * b }.otherwise(c.setAll)  //It's OK\n",
    "}\n",
    "showRtl(new T2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  asBool issue\n",
    "Please note that for 1 bit data operation, the first method is different from the latter two methods.\n",
    "- a.asBits  \n",
    "- a.lsb     \n",
    "- a(0) \n",
    "```scala\n",
    "val a= Bits(1 bits)\n",
    "a.asBits //return new Bool，then tmp := a.lsb\n",
    "a.lsb    //direct operate a(0) bit\n",
    "a(0)     //direct operate a(0) bit\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class T1  extends Component{  \n",
    "  val sel = in Bool()\n",
    "  val a = Reg(Bits(1 bits)) init 0 \n",
    "  when(sel){a.asBool.set()} //generate verilog beyond your expectations\n",
    "}\n",
    "showRtl(new T1)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class T2  extends Component{  \n",
    "  val sel = in Bool()\n",
    "  val a = Reg(Bits(1 bits)) init 0 \n",
    "  when(sel){a(0).set()} \n",
    "  // when(sel){a.lsb.set()}  //also Ok\n",
    "}\n",
    "showRtl(new T2) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. Overlap or Latch?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import scala.collection.mutable.ListBuffer\n",
    "class T2 extends Component{\n",
    "  val a =  in UInt(2 bits)\n",
    "  val Lut = ListBuffer.fill(8)(UInt(8 bits))\n",
    "  (0 to 7).foreach{ i =>      \n",
    "    Lut(i) := i        \n",
    "  }\n",
    "  switch(a){\n",
    "    is(0){\n",
    "        Lut(0) := 3\n",
    "        Lut(2) := 4\n",
    "    }\n",
    "    is(1){\n",
    "        Lut(3) := 3\n",
    "        Lut(4) := 4\n",
    "    }\n",
    "  is(2){\n",
    "        Lut(3) := 3\n",
    "        Lut(4) := 4\n",
    "    } \n",
    "   default{\n",
    "    (0 to 7).foreach{ i =>           \n",
    "      Lut(i) := i        \n",
    "    }\n",
    "   }\n",
    "  }\n",
    "}\n",
    "showRtl(new T2)      "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  val def in Trait\n",
    "**Attation** val cause Error "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait PRNBase {\n",
    "  val size: Int \n",
    "\n",
    "  val Mask = (1 << size) - 1    //attation \n",
    "  val Msb  = (1 << (size - 1))  //attation\n",
    "}\n",
    "\n",
    "object GPS extends PRNBase{\n",
    "    val size = 1023\n",
    "}\n",
    "\n",
    "object BD extends PRNBase{\n",
    "    val size = 2046\n",
    "}\n",
    "BD.Mask toHexString // return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait PRNBase {\n",
    "  val size: Int \n",
    "\n",
    "  def Mask = (1 << size) - 1\n",
    "  def Msb  = (1 << (size - 1))\n",
    "}\n",
    "object BD extends PRNBase{\n",
    "    val size = 11\n",
    "}\n",
    "BD.Mask toHexString"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##   Scala double definition  \n",
    "```scala \n",
    "class TestDoubleDef{\n",
    "  def foo(p:List[String]) = {}\n",
    "  def foo(p:List[Int]) = {}\n",
    "}\n",
    "```\n",
    "**raise Error:**\n",
    "```sh\n",
    "[error] double definition:\n",
    "[error] method foo:(List[String])Unit and\n",
    "[error] method foo:(List[Int])Unit at line 120\n",
    "[error] have same type after erasure: (List)Unit \n",
    "```\n",
    "Solution: https://stackoverflow.com/questions/3307427/scala-double-definition-2-methods-have-the-same-type-erasure/3544060#3544060"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "object MyTransform{\n",
    "  def apply(x: Int ): Double              = x + 0.00 \n",
    "  def apply(x: List[Int] ): List[Double]  = x.map(_+0.00)\n",
    "  def apply(x: List[Double] ): List[Double] = x.map(_+0.00)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Use implict transform**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "case class IntList(list: List[Int])\n",
    "case class DoubleList(list: List[Double])\n",
    "\n",
    "implicit def Il(list: List[Int]) = IntList(list)\n",
    "implicit def Dl(list: List[Double]) = DoubleList(list)\n",
    "\n",
    "object FixTo{\n",
    "  def apply(x: Int ): Double              = x + 0.00 \n",
    "  def apply(x: IntList ): List[Double]    = x.list.map(_+0.00)\n",
    "  def apply(x: DoubleList ): List[Double] = x.list.map(_+0.00)\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val a = FixTo(3)\n",
    "val b = FixTo(DoubleList(List(1,2,3,4,5)))\n",
    "val c = FixTo(List(1,2,3,4,5))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Watch Dog\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class T2  extends Component{ \n",
    "    val a = out Bits(9 bit)\n",
    "    a := 133\n",
    "    class Dog{}\n",
    "    val xiaogou = new Dog\n",
    "\n",
    "}\n",
    "showRtl(new T2) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class T2  extends Component{ \n",
    "   class Dog{\n",
    "      def genTimer(n: Int) = {\n",
    "         val timer = Reg(UInt(n bits)) init 0 \n",
    "         val clearTimer = in Bool()\n",
    "         when(clearTimer){\n",
    "            timer init 0\n",
    "         }.otherwise {\n",
    "            timer := timer + 1\n",
    "         }\n",
    "         (clearTimer,timer)\n",
    "      }\n",
    "   }\n",
    "   val xiaogou = new Dog\n",
    "   val (weigou,timer) = xiaogou.genTimer(8)\n",
    "} \n",
    "showRtl(new T2) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    " class Dog {\n",
    "      def genTimer(n: Int) = {\n",
    "         val timer = Reg(UInt(n bits)) init 0 \n",
    "         val clearTimer = in Bool()\n",
    "         when(clearTimer){\n",
    "            timer init 0\n",
    "         }.otherwise {\n",
    "            timer := timer + 1\n",
    "         }\n",
    "         (clearTimer,timer)\n",
    "      }\n",
    "   }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "why not?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class T2  extends Component{ \n",
    "   val xiaogou =  new Dog\n",
    "   val (weigou,timer) = xiaogou.genTimer(8)\n",
    "} \n",
    "showRtl(new T2) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class T2  extends Component{  \n",
    "   val (weigou,timer) = (new Dog).genTimer(8)\n",
    "} \n",
    "showRtl(new T2) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### pretty print"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "implicit class UtilsExpand(x: HertzNumber) {\n",
    "      def toString0: String = {\n",
    "      x.toBigDecimal match {\n",
    "        case y if y > BigDecimal(1e12) => (y/BigDecimal(1e12)).toDouble + \" THz\"\n",
    "        case y if y > BigDecimal(1e9)  => (y/BigDecimal(1e9)).toDouble + \" GHz\"\n",
    "        case y if y > BigDecimal(1e6)  => (y/BigDecimal(1e6)).toDouble + \" MHz\"\n",
    "        case y if y > BigDecimal(1e3)  => (y/BigDecimal(1e3)).toDouble + \" KHz\"\n",
    "        case _ => x.toBigDecimal + \"Hz\"\n",
    "      }\n",
    "    }\n",
    "  }\n",
    "println((100.21 MHz).toString0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "println(HertzNumber(800010).toString0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "(2 KiB)/7"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "2048/7.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "implicit class ByteExpand(x: BigInt) {\n",
    "    def pretty: String = {\n",
    "      x match {\n",
    "        case y if y >= (BigInt(1) << 80) => (y/(BigInt(1)<<80)) + \" YiB\"\n",
    "        case y if y >= (BigInt(1) << 70) => (y/(BigInt(1)<<70)) + \" ZiB\"\n",
    "        case y if y >= (BigInt(1) << 60) => (y/(BigInt(1)<<60)) + \" EiB\"\n",
    "        case y if y >= (BigInt(1) << 50) => (y/(BigInt(1)<<50)) + \" PiB\"\n",
    "        case y if y >= (BigInt(1) << 40) => (y/(BigInt(1)<<40)) + \" TiB\"\n",
    "        case y if y >= (BigInt(1) << 30) => (y/(BigInt(1)<<30)) + \" GiB\"\n",
    "        case y if y >= (BigInt(1) << 20) => (y/(BigInt(1)<<20)) + \" MiB\"\n",
    "        case y if y >= (BigInt(1) << 10) => (y/(BigInt(1)<<10)) + \" KiB\"\n",
    "        case _ => x + \"Byte\"\n",
    "      }\n",
    "    }\n",
    "  }\n",
    "\n",
    "println((BigInt(1) << 80 Byte).pretty)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "20 GiB"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "BigDecimal(333.001) toBigInt"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Scala",
   "language": "scala",
   "name": "scala"
  },
  "language_info": {
   "codemirror_mode": "text/x-scala",
   "file_extension": ".scala",
   "mimetype": "text/x-scala",
   "name": "scala",
   "nbconvert_exporter": "script",
   "version": "2.12.8"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
